[id].vue 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729
  1. <script setup lang="ts" generic="T extends any, O extends any">
  2. import type { RouteLocationRaw } from 'vue-router'
  3. import request from '~/utils/request'
  4. // import { stepsMap } from '~/composables/steps'
  5. import { user } from '~/store/index'
  6. const props = defineProps<{
  7. id: string
  8. }>()
  9. const ykl_id = props.id
  10. const server = (await request({
  11. url: '/yzy/kmksyjlc/detail',
  12. data: {
  13. ykl_id,
  14. },
  15. })).data.one_info
  16. const isCreateUser = server.create_user_id === user.value.user_id
  17. const ykl_lc = Object.assign(JSON.parse(Object.assign(server.ykl_lc)), { ykl_id })
  18. console.log('ykl_lc : ', ykl_lc)
  19. sessionStorage.setItem('ykl_lc', JSON.stringify(ykl_lc))
  20. const stepsReactiveMap = reactive<unknown[][][]>(ykl_lc.processList)
  21. const steps = reactive(
  22. ykl_lc.ykj_yjlc === '1'
  23. ? [// 先上传后划块
  24. {
  25. title: '组卷考试',
  26. children: [
  27. {
  28. title: '出题组卷',
  29. children: [
  30. { title: '章节知识点出题', optional: true, disabled: true, description: '选择相应的章节知识点从题库中选取题目组成试卷', ifCreateUser: true },
  31. { title: '智能出题', optional: true, disabled: true, description: '填写题型数量难易度等信息系统自动生成试卷', ifCreateUser: true },
  32. { title: '附件出题', optional: true, description: '根据上传附件试卷进行考试', ifCreateUser: true },
  33. ],
  34. },
  35. {
  36. title: '预划考号区域',
  37. children: [
  38. { title: '预划考号区域', optional: false, description: '根据试题内容格式制作相应的答题卡样式', ifCreateUser: true },
  39. { title: '考场设置(可选)', optional: true, description: '根据学生考场分配情况上传' },
  40. ],
  41. },
  42. {
  43. title: '预划流程完成',
  44. children: [
  45. { title: '预划流程完成', optional: false, description: '试卷内容和答题卡已确认,可进行下一步', ifCreateUser: true },
  46. ],
  47. },
  48. ],
  49. },
  50. {
  51. title: '扫描',
  52. children: [
  53. {
  54. title: '答题卡扫描',
  55. children: [
  56. { title: '答题卡扫描', optional: false, description: '启动客户端扫描学生答题卡并进行识别与上传' },
  57. ],
  58. },
  59. {
  60. title: '压缩包上传情况',
  61. children: [
  62. { title: '压缩包上传情况', optional: false, description: '启动客户端扫描试卷形成压缩包打包上传平台' },
  63. ],
  64. },
  65. {
  66. title: '制作答题卡',
  67. children: [
  68. { title: '制作答题卡', optional: false, description: '根据试题内容格式制作相应的答题卡样式', ifCreateUser: true },
  69. ],
  70. },
  71. ],
  72. },
  73. {
  74. title: '制作扫描处理',
  75. children: [
  76. {
  77. title: '答题卡二次扫描',
  78. children: [
  79. { title: '答题卡二次扫描', optional: false, description: '启动客户端二次扫描批阅试卷' },
  80. ],
  81. },
  82. {
  83. title: '平台接收试卷确认',
  84. children: [
  85. { title: '平台接收试卷确认', optional: false, description: '确认试卷已上传' },
  86. ],
  87. },
  88. ],
  89. },
  90. {
  91. title: '阅卷',
  92. children: [
  93. {
  94. title: '批阅任务分配',
  95. children: [
  96. { title: '批阅任务分配', optional: false, description: '对阅卷老师分配批阅任务', ifCreateUser: true },
  97. ],
  98. },
  99. {
  100. title: '阅卷',
  101. children: [
  102. { title: '阅卷', optional: false, description: '查看批阅进度查看我的批阅任务' },
  103. ],
  104. },
  105. ],
  106. },
  107. {
  108. title: '成绩',
  109. children: [
  110. {
  111. title: '成绩发布',
  112. children: [
  113. { title: '成绩发布', optional: false, description: '成绩汇总发布到分析平台', ifCreateUser: true },
  114. ],
  115. },
  116. {
  117. title: '修改成绩',
  118. children: [
  119. { title: '修改成绩', optional: false, description: '考试成绩发布后三天内可修改', ifCreateUser: true },
  120. ],
  121. },
  122. {
  123. title: '考试关闭',
  124. children: [
  125. { title: '考试关闭', optional: false, description: '最后考试结束关闭考试', ifCreateUser: true },
  126. ],
  127. },
  128. ],
  129. },
  130. ]
  131. : [// 先划块后上传
  132. {
  133. title: '组卷考试',
  134. children: [
  135. {
  136. title: '出题组卷',
  137. children: [
  138. { title: '章节知识点出题', optional: true, disabled: true, description: '选择相应的章节知识点从题库中选取题目组成试卷', ifCreateUser: true },
  139. { title: '智能出题', optional: true, disabled: true, description: '填写题型数量难易度等信息系统自动生成试卷', ifCreateUser: true },
  140. { title: '附件出题', optional: true, description: '根据上传附件试卷进行考试', ifCreateUser: true },
  141. ],
  142. },
  143. {
  144. title: '制作答题卡',
  145. children: [
  146. { title: '制作答题卡', optional: false, description: '根据试题内容格式制作相应的答题卡样式', ifCreateUser: true },
  147. { title: '考场设置(可选)', optional: true, description: '根据学生考场分配情况上传' },
  148. ],
  149. },
  150. {
  151. title: '组卷流程完成',
  152. children: [
  153. { title: '组卷流程完成', optional: false, description: '试卷内容和答题卡已确认,可进行下一步', ifCreateUser: true },
  154. ],
  155. },
  156. ],
  157. },
  158. {
  159. title: '扫描',
  160. children: [
  161. {
  162. title: '答题卡扫描',
  163. children: [
  164. { title: '连接扫描仪', optional: false, description: '启动客户端扫描学生答题卡并进行识别与上传' },
  165. ],
  166. },
  167. {
  168. title: '平台接收试卷确认',
  169. children: [
  170. { title: '平台接收试卷确认', optional: false, description: '时间及试题均接收并识别入库完成' },
  171. ],
  172. },
  173. ],
  174. },
  175. {
  176. title: '阅卷',
  177. children: [
  178. {
  179. title: '批阅任务分配',
  180. children: [
  181. { title: '批阅任务分配', optional: false, description: '对阅卷老师分配批阅任务', ifCreateUser: true },
  182. ],
  183. },
  184. {
  185. title: '阅卷',
  186. children: [
  187. { title: '阅卷', optional: false, description: '查看批阅进度查看我的批阅任务' },
  188. ],
  189. },
  190. ],
  191. },
  192. {
  193. title: '成绩',
  194. children: [
  195. {
  196. title: '成绩发布',
  197. children: [
  198. { title: '成绩发布', optional: false, description: '成绩汇总发布到分析平台', ifCreateUser: true },
  199. ],
  200. },
  201. {
  202. title: '修改成绩',
  203. children: [
  204. { title: '修改成绩', optional: false, description: '考试成绩发布后三天内可修改', ifCreateUser: true },
  205. ],
  206. },
  207. {
  208. title: '考试关闭',
  209. children: [
  210. { title: '考试关闭', optional: false, description: '最后考试结束关闭考试', ifCreateUser: true },
  211. ],
  212. },
  213. ],
  214. },
  215. ],
  216. )
  217. let gid = $ref<number>(0)
  218. let pids = $ref<number[]>([])
  219. // const cid = $ref(-1)
  220. function getGid() {
  221. return stepsReactiveMap.findLastIndex(item => item.some(subItem => subItem.some(subSubItem => judgeStepCompleted(subSubItem))))
  222. }
  223. function getPids() {
  224. return stepsReactiveMap.map((item, idx) => (idx < gid ? 1 : 0) + item.findLastIndex(subItem => subItem.some(subSubItem => judgeStepCompleted(subSubItem))))
  225. }
  226. watch(() => stepsReactiveMap, (val) => {
  227. gid = getGid()
  228. pids = getPids()
  229. }, {
  230. immediate: true,
  231. deep: true,
  232. })
  233. let currentStep = $ref<number>(gid)
  234. const CardsRef = $shallowRef<Array<Array<typeof import('~/components/TheCard.vue')['default']>>>([])
  235. const lineList: any[][][] = []
  236. // onMounted(() => {
  237. // CardsRef.forEach((cards, idx) => {
  238. // if (idx === CardsRef.length - 1)
  239. // return
  240. // cards.forEach((card, idy) => {
  241. // const line = new LeaderLine(
  242. // card.getDom(),
  243. // CardsRef[idx + 1][0].getDom(),
  244. // {
  245. // path: 'grid',
  246. // endPlug: 'behind',
  247. // size: 6,
  248. // startSocket: 'right',
  249. // endSocket: 'left',
  250. // color: stepsReactiveMap[currentStep][idx][idy] ? '#003eee' : '#a3a3a3',
  251. // },
  252. // )
  253. // lineList.push(line)
  254. // })
  255. // })
  256. // })
  257. function handleSwitchCurrentStep(id: number) {
  258. currentStep = id
  259. }
  260. onMounted(() => {
  261. watch(() => currentStep, (val, old) => {
  262. if (old !== undefined)
  263. lineList[old].forEach(lines => lines.forEach(line => line?.hide('none')))
  264. if (lineList[val]?.length) {
  265. lineList[val].forEach(lines => lines.forEach(line => line?.show('none')))
  266. }
  267. else {
  268. nextTick(() => {
  269. CardsRef.forEach((cards, idx) => {
  270. if (idx === CardsRef.length - 1)
  271. return
  272. cards.forEach((card, idy) => {
  273. if (card === null || CardsRef[idx + 1][0] === null)
  274. return
  275. const line = new LeaderLine(
  276. card.getDom(),
  277. CardsRef[idx + 1][0].getDom(),
  278. {
  279. path: 'grid',
  280. endPlug: 'behind',
  281. size: 6,
  282. startSocket: 'right',
  283. endSocket: 'left',
  284. color: stepsReactiveMap[currentStep][idx][idy] ? '#003eee' : '#a3a3a3',
  285. },
  286. )
  287. line?.position()
  288. if (stepsReactiveMap[currentStep][idx][idy])
  289. document.querySelectorAll('.leader-line')[line._id as number - 1]?.classList.add('z10')
  290. lineList[val] = lineList[val] || []
  291. lineList[val][idx] = lineList[val][idx] || []
  292. lineList[val][idx][idy] = line
  293. })
  294. })
  295. })
  296. }
  297. }, {
  298. immediate: true,
  299. })
  300. })
  301. const router = useRouter()
  302. function routerPush(path: RouteLocationRaw) {
  303. router.push(path)
  304. }
  305. function windowPushState(path: string) {
  306. // !未启用
  307. sessionStorage.setItem('historyLocation', location.href)
  308. window.open(`${location.origin}/${path}`, '_self')
  309. // location.replace(`${location.origin}/${path}`)
  310. // window.history.pushState(null, '', `${location.origin}/${path}`)
  311. }
  312. // 采取如下方式主要由于chrome下history.back()不会重新load页面
  313. window.addEventListener('pageshow', (e) => {
  314. if (e.persisted)
  315. window.location.reload()
  316. })
  317. function handleValidTask(currentStep: number, idx: number, idy: number) {
  318. let lastIdx = idx
  319. let lastStep = currentStep
  320. const lastTasks = idx > 0 ? stepsReactiveMap[currentStep][lastIdx = idx - 1] : currentStep > 0 ? stepsReactiveMap[lastStep = currentStep - 1][lastIdx = stepsReactiveMap[currentStep - 1].length - 1] : []
  321. if (lastTasks.every((item, idz) => {
  322. if (steps[lastStep].children[lastIdx].children[idz].optional)
  323. return true
  324. else
  325. return !!item
  326. })) {
  327. sessionStorage.setItem('StepId', JSON.stringify({ gid: currentStep, pid: idx, cid: idy }))
  328. return true
  329. }
  330. else {
  331. ElMessage({
  332. message: '请先完成之前的任务',
  333. type: 'warning',
  334. grouping: true,
  335. })
  336. return false
  337. }
  338. }
  339. function judgeIfContinueDoTask(gid: number, pid: number, idy: number) {
  340. const currentTask = steps[gid].children[pid].children[idy]
  341. const continueDoTask = !currentTask.ifCreateUser || isCreateUser
  342. if (!continueDoTask) {
  343. ElMessage({
  344. message: '只有考试创建人才能操作',
  345. type: 'warning',
  346. grouping: true,
  347. })
  348. }
  349. return continueDoTask
  350. }
  351. function beforeClickTask(gid: number, pid: number, idy: number) {
  352. const continueDoTask = judgeIfContinueDoTask(gid, pid, idy)
  353. if (!continueDoTask)
  354. return false
  355. else
  356. return handleValidTask(gid, pid, idy)
  357. }
  358. function judgeTaskCanClick(gid: number, pid: number, idy: number) {
  359. const continueDoTask = judgeIfContinueDoTask(gid, pid, idy)
  360. if (!continueDoTask) {
  361. return false
  362. }
  363. else {
  364. let lastIdx = pid
  365. let lastStep = currentStep
  366. const lastTasks = pid > 0 ? stepsReactiveMap[currentStep][lastIdx = pid - 1] : currentStep > 0 ? stepsReactiveMap[lastStep = currentStep - 1][lastIdx = stepsReactiveMap[currentStep - 1].length - 1] : []
  367. if (lastTasks.every((item, idz) => {
  368. if (steps[lastStep].children[lastIdx].children[idz].optional)
  369. return true
  370. else
  371. return !!item
  372. }))
  373. return true
  374. else
  375. return false
  376. }
  377. }
  378. function judgeStepCompleted(val: unknown) {
  379. return (!!val) || (typeof val === 'object' && !!(val?.value))
  380. }
  381. function handleCompleteTask(gid: number, pid: number, cid: number, val?: unknown): Promise<any> {
  382. const _ykl_lc_ = JSON.parse(sessionStorage.getItem('ykl_lc')!)
  383. _ykl_lc_.processList[gid][pid][cid] = val || 1
  384. return request({
  385. url: '/yzy/kmksyjlc/save',
  386. data: {
  387. ykl_id,
  388. yk: {
  389. ykl_lc: JSON.stringify(_ykl_lc_),
  390. },
  391. },
  392. }).then((res) => {
  393. if (res.code === '1') {
  394. ElMessage({
  395. message: '操作成功',
  396. type: 'success',
  397. grouping: true,
  398. })
  399. sessionStorage.setItem('ykl_lc', JSON.stringify(_ykl_lc_))
  400. stepsReactiveMap[gid][pid][cid] = val || 1
  401. return res
  402. }
  403. }).catch(() => {
  404. ElMessage({
  405. message: '操作失败',
  406. type: 'error',
  407. grouping: true,
  408. })
  409. })
  410. }
  411. async function handleJumpTask(gid: number, pid: number, idy: number) {
  412. // 验证任务是否完成
  413. if (judgeStepCompleted(stepsReactiveMap[gid][pid][idy])) {
  414. return ElMessage({
  415. message: '该任务已完成',
  416. type: 'warning',
  417. grouping: true,
  418. })
  419. }
  420. // stepsReactiveMap[gid][pid][idy] = 1
  421. const res = await handleCompleteTask(gid, pid, idy)
  422. if (res.code === '1') {
  423. if (pid !== stepsReactiveMap[gid].length - 1) {
  424. const line = lineList[gid][pid][idy]
  425. line.setOptions({ color: '#003eee' })
  426. document.querySelectorAll('.leader-line')[line._id - 1]?.classList.add('z10')
  427. }
  428. }
  429. return res
  430. }
  431. onBeforeRouteLeave(() => {
  432. lineList.forEach(lines => lines.forEach(line => line.forEach(l => l?.hide('none'))))
  433. })
  434. function handleCompleteTaskAuto() {
  435. const { gid, pid, cid } = JSON.parse(sessionStorage.getItem('StepId')!)
  436. return handleJumpTask(gid, pid, cid)
  437. }
  438. const TaskEventMap: { [key: string]: () => void } = {
  439. '章节知识点出题': () => {
  440. ElMessage.info('暂未开放')
  441. },
  442. '智能出题': () => {
  443. ElMessage.info('暂未开放')
  444. },
  445. '附件出题': () => {
  446. routerPush({ name: 'process-fjct-ze_id-zs_id', params: { ze_id: ykl_lc.ze_id, zs_id: ykl_lc.zs_id } })
  447. },
  448. '预划考号区域': () => {
  449. windowPushState(`${window.GLOBAL_CONFIG.build}/dtk/index.html`)
  450. },
  451. '制作答题卡': () => {
  452. windowPushState(`${window.GLOBAL_CONFIG.build}/dtk/index.html`)
  453. },
  454. '考场设置(可选)': () => {
  455. windowPushState(`${window.GLOBAL_CONFIG.base}/exam-room-set.html?id=${ykl_lc.ze_id}`)
  456. },
  457. '预划流程完成': async () => {
  458. await handleCompleteTaskAuto()
  459. currentStep = 1
  460. },
  461. '组卷流程完成': async () => {
  462. await handleCompleteTaskAuto()
  463. currentStep = 1
  464. },
  465. // 先上传后划块
  466. '答题卡扫描': () => {
  467. window.open(`BozeduYuejuan://${user.value.token},${ykl_lc.ze_id},${window.GLOBAL_CONFIG.yzy},upload_papers`, '_blank')
  468. handleCompleteTaskAuto()
  469. },
  470. '压缩包上传情况': () => {
  471. // todo: 需调整【压缩包】上传情况
  472. routerPush(`/process/ysb/${ykl_lc.ykl_id}/${ykl_lc.ze_id}`)
  473. handleCompleteTaskAuto()
  474. },
  475. '答题卡二次扫描': () => {
  476. window.open(`BozeduYuejuan://${user.value.token},${ykl_lc.ze_id},${window.GLOBAL_CONFIG.yzy},review_papers`, '_blank')
  477. handleCompleteTaskAuto()
  478. },
  479. // 先划块后上传 老流程
  480. '连接扫描仪': () => {
  481. window.open(`BozeduYuejuan://${user.value.token},${ykl_lc.ze_id},${window.GLOBAL_CONFIG.yzy}`, '_blank')
  482. handleCompleteTaskAuto()
  483. },
  484. '平台接收试卷确认': async () => {
  485. await handleCompleteTaskAuto()
  486. windowPushState(`${window.GLOBAL_CONFIG.base}/marking-answer-sheet-liankao.html?ze_id=${ykl_lc.ze_id}`)
  487. },
  488. '批阅任务分配': () => {
  489. windowPushState(`${window.GLOBAL_CONFIG.base}/taskassignment-liankao.html`)
  490. },
  491. '阅卷': () => {
  492. windowPushState(`${window.GLOBAL_CONFIG.base}/single-review-liankao.html?ze_id=${ykl_lc.ze_id}`)
  493. },
  494. '成绩发布': () => {
  495. let loading = false
  496. ElMessageBox.confirm('选择实时发布时需等待浏览器处理结束;正常发布则无需等待', '选择发布成绩的方式', {
  497. confirmButtonText: '实时发布',
  498. cancelButtonText: '正常发布',
  499. type: 'info',
  500. distinguishCancelAndClose: true,
  501. beforeClose: async (action, instance, done) => {
  502. if (action === 'confirm') {
  503. // 实时发布
  504. console.log('实时发布')
  505. instance.confirmButtonLoading = loading = true
  506. try {
  507. const res0 = await request({
  508. url: '/openapi/crontab/datamaker.php',
  509. data: {
  510. ykl_id,
  511. },
  512. })
  513. if (res0.code !== '1')
  514. throw new Error(res0.msg)
  515. const res1 = await handleCompleteTaskAuto()
  516. if (res1.code !== '1')
  517. throw new Error(res1.msg)
  518. ykl_lc.ykl_stat_ready = 2
  519. ElMessage.success('发布成功')
  520. }
  521. catch (error) {
  522. console.error('发布失败', error)
  523. }
  524. instance.confirmButtonLoading = loading = false
  525. }
  526. else if (action === 'cancel') {
  527. // 正常发布
  528. console.log('正常发布')
  529. instance.cancelButtonLoading = loading = true
  530. try {
  531. const res0 = await request({
  532. url: '/yzy/kmksyjlc/save',
  533. data: {
  534. ykl_id,
  535. yk: {
  536. ykl_sffbcj: 1,
  537. },
  538. },
  539. })
  540. if (res0.code !== '1')
  541. throw new Error(res0.msg)
  542. const res1 = await handleCompleteTaskAuto()
  543. if (res1.code !== '1')
  544. throw new Error(res1.msg)
  545. ykl_lc.ykl_stat_ready = 1
  546. ElMessage.success('发布中...')
  547. }
  548. catch (error) {
  549. console.error('发布失败', error)
  550. }
  551. instance.cancelButtonLoading = loading = false
  552. }
  553. else {
  554. console.log('取消发布')
  555. return loading ? ElMessage.warning('发布中,请勿关闭弹窗') : done()
  556. }
  557. },
  558. })
  559. },
  560. '修改成绩': async () => {
  561. await handleCompleteTaskAuto()
  562. routerPush({ name: 'process-xgcj-id', params: { id: ykl_lc.ze_id } })
  563. },
  564. '考试关闭': () => {
  565. ElMessageBox({
  566. title: '提示',
  567. message: '确定要关闭考试吗?',
  568. type: 'warning',
  569. showCancelButton: true,
  570. confirmButtonText: '确定',
  571. cancelButtonText: '取消',
  572. }).then(() => {
  573. const { gid, pid, cid } = JSON.parse(sessionStorage.getItem('StepId')!)
  574. handleJumpTask(gid, pid, cid)
  575. })
  576. },
  577. }
  578. </script>
  579. <template>
  580. <div class="w-full min-h-screen flex flex-col bg-white">
  581. <NavHeader />
  582. <bread-crumb />
  583. <div class="flex-auto w-1200px m-auto">
  584. <div class="flex flex-auto justify-start divide-x-4 divide-blue-700">
  585. <div class="h-full w-220px">
  586. <el-steps direction="vertical" :active="currentStep">
  587. <el-step
  588. v-for="({ title, children }, idx) in steps" :key="title" class="cursor-pointer hover:bg-light-600"
  589. :class="idx === currentStep && 'bg-light-400'" @click="handleSwitchCurrentStep(idx)"
  590. >
  591. <template #title>
  592. <div class="mb-4 font-normal">
  593. {{ title }}
  594. </div>
  595. </template>
  596. <template #description>
  597. <el-steps direction="vertical" :space="40" :active="pids[idx]">
  598. <el-step v-for="({ title }) in children" :key="title">
  599. <template #title>
  600. <div class="font-normal">
  601. {{ title }}
  602. </div>
  603. </template>
  604. </el-step>
  605. </el-steps>
  606. </template>
  607. </el-step>
  608. </el-steps>
  609. </div>
  610. <div class="flex-auto p-4">
  611. <div class="h-full flex justify-between">
  612. <div
  613. v-for="(step, idx) in steps[currentStep].children " :key="idx"
  614. class="h-full flex flex-col justify-evenly"
  615. >
  616. <the-card
  617. v-for="(task, idy) in step.children " :key="idy"
  618. :ref="el => { CardsRef[idx] = CardsRef[idx] || []; CardsRef[idx][idy] = el as any }" :title="task.title"
  619. :description="task.description" :completed="judgeStepCompleted(stepsReactiveMap[currentStep][idx][idy])"
  620. >
  621. <template #operate>
  622. <template v-if="task.title === '预划考号区域'">
  623. <div
  624. class="min-w-60px cursor-pointer rounded bg-light-50 py-3px text-center text-xs"
  625. @click="beforeClickTask(currentStep, idx, idy) && TaskEventMap[task.title]()"
  626. >
  627. {{ judgeStepCompleted(stepsReactiveMap[currentStep][idx][idy]) ? '已经完成' : '立即开始' }}
  628. </div>
  629. <div
  630. class="min-w-60px cursor-pointer rounded bg-light-50 py-3px text-center text-xs"
  631. @click="beforeClickTask(currentStep, idx, idy) && handleJumpTask(currentStep, idx, idy)"
  632. >
  633. {{ '跳过' }}
  634. </div>
  635. </template>
  636. <template v-else-if="task.title === '成绩发布'">
  637. <div
  638. class="min-w-60px cursor-pointer rounded bg-light-50 py-3px text-center text-xs"
  639. @click="beforeClickTask(currentStep, idx, idy) && (TaskEventMap[task.title] ? TaskEventMap[task.title]() : handleCompleteTaskAuto())"
  640. >
  641. {{ judgeStepCompleted(stepsReactiveMap[currentStep][idx][idy])
  642. ? (ykl_lc.ykl_stat_ready === 1 ? '发布中…' : '已发布') : '成绩发布' }}
  643. </div>
  644. </template>
  645. <template v-else>
  646. <div
  647. class="min-w-60px rounded bg-light-50 py-3px text-center text-xs"
  648. :class="task.disabled ? 'cursor-not-allowed' : 'cursor-pointer'"
  649. @click="beforeClickTask(currentStep, idx, idy) && (TaskEventMap[task.title] ? TaskEventMap[task.title]() : handleCompleteTaskAuto())"
  650. >
  651. {{ judgeStepCompleted(stepsReactiveMap[currentStep][idx][idy]) ? '已经完成' : task.disabled ? '暂未开放'
  652. : '立即开始'
  653. }}
  654. </div>
  655. </template>
  656. </template>
  657. <template #tip>
  658. <template v-if="task.title === '成绩发布'">
  659. <div class="mt-2 flex flex-col items-start px-1 text-xs space-y-1" style="--el-font-size-base:10px">
  660. <xgstda :disabled="!judgeTaskCanClick(currentStep, idx, idy)" />
  661. <szcjckqx :disabled="!judgeTaskCanClick(currentStep, idx, idy)" />
  662. <bjqk :disabled="!judgeTaskCanClick(currentStep, idx, idy)" />
  663. </div>
  664. </template>
  665. </template>
  666. </the-card>
  667. </div>
  668. </div>
  669. </div>
  670. </div>
  671. </div>
  672. <commonFooter />
  673. </div>
  674. </template>
  675. <style scoped>
  676. :deep(.el-step:last-of-type .el-step__line) {
  677. display: block;
  678. }
  679. :deep(.el-step__description .el-step:last-of-type .el-step__line) {
  680. display: none;
  681. }
  682. </style>
  683. <route>
  684. {
  685. meta: {
  686. title: '考试流程',
  687. breadcrumb: true,
  688. },
  689. }
  690. </route>